Developing mobile applications is a tricky business; having the right orientation and technical foundation to start makes all the difference. Given the multitude of technology alternatives, mobile developers are increasingly realizing it is no longer feasible to specialize in one given platform. Traditional, native platforms (iOS, Android, Windows Phone 7, Windows Mobile, etc.) are unnecessarily complex and are pinned to a software stack that requires a steep learning curve and many tricks to work around their inherent ties to their non-web foundation. If developing for native platforms weren’t enough of a drive-away force, their tightly controlled application deployment and sales channels make things even worse.
Luckily, there are at least two main ways out of the native platform trap. One way is using more familiar programming languages and development environments and translating to native code (typically done for iOS development, with solutions like MonoTouch). To some degree, this relies on learning similarly complex APIs and having to deal with the quirks of fitting the native device capabilities over those APIs to perform the mapping correctly.
Another way out is web-based mobile applications. They eliminate the need for platform-specific technologies with their crippled development environments, and put your applications on a foundation based on common web standards such as HTML5, CSS3 and JavaScript, greatly simplifying cross-platform expansion. One thing we have learned from the web is it can’t and shouldn’t be contained: the capabilities and services in it must be consumable from whatever device you are using. You can expect future mobile platform versions and operating systems will further blur the traditional boundary between “native” and “web” applications.
Currently, developing cross-platform web-based mobile applications with solutions like PhoneGap, Rhomobile, or AppMobi relies on exposing native device functionality through JavaScript APIs and rendering your web applications written against those APIs through a native shell application. This should sound like an attractive proposition, but demands you develop your applications in JavaScript. DSL-based alternatives and a good discussion are available in the state of the art in mobile web application development article on InfoQ.
WebSharper
WebSharper aims to solve several of the above problems. First, it enables you to develop your entire web or mobile application in F# enjoying its concise syntax and powerful functional constructs, cutting most of the code you have been used to writing. Second, it gives you a rich set of abstractions and eDSL syntax for common web-related chores, such as composing HTML, defining web forms, managing required resources, handling URLs safely, and many others. What makes it especially well-suited to larger, enterprise-grade application development is these abstractions are strongly typed: for instance, constructing web forms yielding data values of the wrong type, or trying to add form validation to the wrong input control will yield compile-time errors, again greatly reducing development time.
Sitelets – composing websites
WebSharper 2.0 introduced sitelets, implementing type-safe, first-class website values. A sitelet is defined over a union “action” type that encompasses all pages/content in the site it represents, and contains a router and a controller to map URL requests back and forth between actions and actual content.
(Click on the image to enlarge it)
Figure 1: Sample website from the WebSharper Visual Studio template
Here is a simple Action type, taken from the sample sitelet application template, which comes with your WebSharper installer, defining the small sample website in Figure 1:
/// Actions that correspond to the different pages in the site. type Action = | Home | Contact | Protected | Login of option<Action> | Logout | Echo of string
Content can be arbitrary, you can return any file, or XML or HTML content, depending on what purpose your sitelet serves, such as RESTful services. You can manually construct your router and controller if you need fine-grained control over your URL space, or have them inferred automatically from your action type, or both by combining smaller sitelets using either strategy.
Sitelets also come with a type-safe templating language based on XML markup with special placeholders. These files (ending with .template.xml) are automatically converted to F# code and included in your build when you add them to your WebSharper Visual Studio solution.
Consider the following template markup in Skin.template.xml, again from the sample sitelet application template:
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Your site title</title> <link href="~/themes/reset.css" rel="stylesheet" type="text/css" /> <link href="~/themes/site.css" rel="stylesheet" type="text/css" /> </head> <body> <div> <div id="loginInfo">${LoginInfo}</div><div id="header">
<div id="banner">${Banner}</div>
<div id="menu">${Menu}</div>
<div class="closer"></div>
</div><div id="main-container">
<div id="main">${Main}</div>
<div id="sidebar">${Sidebar}</div>
<div class="closer"></div>
</div><div id="footer">${Footer}</div>
</div>
</body>
</html>
This creates a Templates.Skin module in the default namespace, available for composing markup snippets into the placeholders. Consider the following function that takes the title and the main content of a page and constructs a page value using the generated template function:
/// A template function that renders a page with a menu bar, based on the Skin template. let Template title main : Content<Action> = let menu (ctx: Context<Action>)= [ A [Action.Home |> ctx.Link |> HRef] -< [Text "Home"] A [Action.Contact |> ctx.Link |> HRef] -< [Text "Contact"] A [Action.Echo "Hello" |> ctx.Link |> HRef] -< [Text "Say Hello"] A [Action.Protected |> ctx.Link |> RandomizeUrl |> HRef] -< [Text "Protected"] A ["~/LegacyPage.aspx" |> ctx.ResolveUrl |> HRef] -< [Text "ASPX Page"] ] |> List.map (fun link -> Label [Class "menu-item"] -< [link] ) Templates.Skin.Skin (Some title) { LoginInfo = Widgets.LoginInfo Banner = fun ctx -> [H2 [Text title]] Menu = menu Main = main Sidebar = fun ctx -> [Text "Put your side bar here"] Footer = fun ctx -> [Text "Your website. Copyright (c) 2011 YourCompany.com"] }
Here, main is a function yielding a list of XML/HTML elements, similar to the menu computed in the inner menu function. Also, note how the context object can map the various Action shapes to safe URLs (the pipe |> operator is used to send an argument to a function, e.g. x |> f is equivalent to f(x)).
You can define all kinds of tiny abstractions to make your application code more concise. Here is a link operator (=>) to create a hyperlink:
/// A helper function to create a hyperlink let ( => ) title href = A [HRef href] -< [Text title]
Now you could define the home page in your sitelet as:
/// The pages of this website. module Pages =/// The home page.
let HomePage : Content<Action> =
Template "Home" <| fun ctx ->
[
H1 [Text "Welcome to our site!"]
"Let us know how we can contact you" => ctx.Link Action.Contact
]
...
Once all your pages are defined, you can create a sitelet to represent your website. Here you are combining three smaller sitelets:
let EntireSite =// A simple sitelet for the home page, available at the root of the application.
let home =
Sitelet.Content "/" Action.Home Pages.HomePage// An automatically inferred sitelet created for the basic parts of the application.
let basic =
Sitelet.Infer <| fun action ->
match action with
| Action.Contact -> Pages.ContactPage
| Action.Echo param -> Pages.EchoPage param
| Action.Login action -> Pages.LoginPage action
| Action.Logout ->
// Logout user and redirect to home
UserSession.Logout ()
Content.Redirect Action.Home
| Action.Home -> Content.Redirect Action.Home
| Action.Protected -> Content.ServerError// A sitelet for the protected content that requires users to log in first.
let authenticated =
let filter : Sitelet.Filter<Action> =
{
VerifyUser = fun _ -> true
LoginRedirect = Some >> Action.Login
}Sitelet.Protect filter
<| Sitelet.Content "/protected" Action.Protected Pages.ProtectedPage// Compose the above sitelets into a larger one.
Sitelet.Sum
[
home
authenticated
basic
]
With the above sitelet, all you need is to annotate it as a sitelet and, voila, your site can be served from an ASP.NET-based web container (you get the necessary Web.Config changes in the WebSharper Visual Studio template):
/// Expose the main sitelet so it can be served. /// This needs an IWebsite type and an assembly level annotation. type SampleWebsite() = interface IWebsite<SampleSite.Action> with member this.Sitelet = EntireSite member this.Actions = [][<assembly: WebsiteAttribute(typeof<SampleWebsite>)>]
do ()
Formlets – composing first-class type-safe forms
Formlets, a recent formalism from academia, have been an integral part of WebSharper, one of the first frameworks to implement them. Formlets represent first-class, type-safe, composable data forms, much different from the less strictly-typed approaches you may have been using with ASP.NET or other web frameworks. The WebSharper implementation also includes dependent formlets, where one part of the formlet depends on another such as on a dropdown box with multiple options or values entered in an input box; and flowlets, a custom layout that renders each formlet step in a formlet computation expression, a monadic construct in F#, in a wizard-like sequence.
Here is a simple input formlet returning a string value with various enhancements applied incrementally:
let nameF = Controls.Input "" |> Validator.IsNotEmpty "Empty name not allowed" |> Enhance.WithValidationIcon |> Enhance.WithTextLabel "Name"
Formlets can be mapped to return values of any type, for instance a percentage input control might return float values between 0 and 100, or a combo box might yield one of the shapes of a discriminated union (with or without tagged values). You can compose formlets into larger formlets in various ways. The simplest way is using the Formlet.Yield function, which wraps a value of any type into a formlet of that type, in combination with the <*> operator that composes two (or via subsequent calls multiple) formlets:
Formlet.Yield (fun v1 v2 ... vn -> <compose all v’s>) <*> formlet1 <*> formlet2 ... <*> formletn
Here is an example of taking a person’s information (name and email), with basic client-side validation:
type Person = { Name: string Email: string }[<JavaScript>]
let PersonFormlet () : Formlet<Person> =
let nameF =
Controls.Input ""
|> Validator.IsNotEmpty "Empty name not allowed"
|> Enhance.WithValidationIcon
|> Enhance.WithTextLabel "Name"
let emailF =
Controls.Input ""
|> Validator.IsEmail "Please enter valid email address"
|> Enhance.WithValidationIcon
|> Enhance.WithTextLabel "Email"
Formlet.Yield (fun name email -> { Name = name; Email = email })
<*> nameF
<*> emailF
|> Enhance.WithSubmitAndResetButtons
|> Enhance.WithLegend "Add a New Person"
|> Enhance.WithFormContainer
The result when embedded in a sitelet page is in Figure 2. Note the styling is provided by a dependent CSS resource automatically added to your page when you reference formlet code (actually, when you call Enhance.WithFormContainer). WebSharper’s sophisticated dependency tracking collects dependent resources for a given page automatically as they are served. This is very convenient and saves a great deal of time and effort when using various WebSharper extensions to third-party JavaScript libraries, essentially eliminating the need to manually track what needs to be included in a page.
Figure 2: A simple formlet with validation and various enhancements
The [<JavaScript>] annotation in the above formlet example directs WebSharper to translate this code block to JavaScript. The validators each control is enhanced with are part of the WebSharper formlet library and they provide client-side validation, so Validator.IsEmail will make sure only valid email addresses are entered before the formlet reaches an accepting state. You can also make calls to your own user-defined functions, or provide additional validation by further enhancing the formlet at hand. If a function is annotated with [<Rpc>] and is called from client-side code, WebSharper outputs code to perform an RPC call and handles the passing of values between the client and the server side automatically. You can work with arbitrarily complex F# values, such as nested lists, maps, sets, or sequences seamlessly without having to worry about how they are mapped. This makes programming client and server-side code uniform and greatly reduces development time. In fact, you typically develop client and server code in the same F# file, organized into different modules under the same namespace.
You can use a number of WebSharper patterns for developing client-server applications, we usually recommend working with sitelets and formlets and give various coding guidelines for maximizing your efficiency, but you may develop hybrid applications as well with a significant ASP.NET code base, or enhance your existing ASP.NET applications with WebSharper-based functionality.
Building form abstractions for your needs
Occasionally, you may need to step outside the boundaries of the standard WebSharper formlet library to implement the forms (or the entire UI) for your application. For instance, you may want to render your formlets using different input controls and simple CSS overrides are no longer sufficient to get the look and feel you desire. Other times, you would like to reuse existing JavaScript control libraries such as Ext JS, YUI, or jQuery UI to give a more elaborate look and feel. WebSharper comes with a large number of extensions to various third-party libraries including these, and some extensions come with a formlet abstraction as well.
Here is a short example utilizing the Formlets for jQuery Mobile extension, using the Formlet.Do computation expression with a flowlet layout, and the familiar Formlet.Yield composition to weave together a 2-step login sequence:
let loginSequenceF = Formlet.Do { let! username, password, remember = Formlet.Yield (fun user pass remember -> user, pass, remember) <*> (Controls.TextField "" Theme.C "Username: " |> Validator.IsNotEmpty "Username cannot be empty!") <*> (Controls.Password "" Theme.C "Password: " |> Validator.IsRegexMatch "^[1-4]{4,}[0-9]$" "The password is wrong!") <*> Controls.Checkbox true Theme.C "Keep me logged in " |> Enhance.WithSubmitButton "Log in" Theme.C let rememberText = if remember then "" else "not " do! Formlet.OfElement (fun _ -> Div [ H3 [Text ("Welcome " + username + "!")] P [Text ("We will " + rememberText + "keep you logged in.")] ]) } |> Formlet.Flowlet
You can compose this login sequence into HTML markup, using the necessary jQuery Mobile attributes (which you can nicely abstract away with a few more lines of code), that you can then add to your sitelet page:
Div [HTML5.Attr.Data "role" "page"] -< [ Div [HTML5.Attr.Data "role" "header"] -< [ H1 [Text "WebSharper Formlets for jQuery Mobile"]> ]Div [HTML5.Attr.Data "role" "content"] -< [
loginSequenceF
]Div [HTML5.Attr.Data "role" "footer"] -< [
P [Attr.Style "text-align: center;"] -< [Text "IntelliFactory"]
]
]
Once you tune the mobile configuration file in your WebSharper mobile project to produce an Android package (you can also choose Windows Phone 7) and install it on your phone you get what’s depicted in Figure 3.
Figure 3: jQuery Mobile formlets running on Android
Using the WebSharper mobile APIs and third-party map controls
Formlets or sitelets greatly simplify your web and mobile development, and give you robust, type-safe, and composable abstractions to model parts of your application. Another fundamental WebSharper abstraction are pagelets, the building blocks of formlets. Pagelets represent first-class, composable client-side markup and behavior. A WebSharper pagelet is compatible with ASP.NET controls and can be embedded directly into ASP.NET markup as well.
Here is an example of a pagelet that implements a map control depicted in Figure 4:
open IntelliFactory.WebSharper open IntelliFactory.WebSharper.Bing open IntelliFactory.WebSharper.Html open IntelliFactory.WebSharper.JQuery open IntelliFactory.WebSharper.Mobiletype CurrentLocationControl() =
inherit Web.Control()[<JavaScript>]
override this.Body =
let screenWidth = JQuery.Of("body").Width()let MapOptions =
Bing.MapViewOptions(
Credentials = bingMapsKey,
Width = screenWidth - 10,
Height = screenWidth - 10,
Zoom = 16)let label = H2 []
let setMap (map : Bing.Map) =
let updateLocation() =// Gets the current location
let loc = Mobile.GetLocation()// Sets the label to be the address of the current location
Rest.RequestLocationByPoint(<<your-bingmaps-key>>, loc.Lat, loc.Long, ["Address"],
fun result ->
let locInfo = result.ResourceSets.[0].Resources.[0]
label.Text <- "You are currently at " + JavaScript.Get "name" locInfo)// Adds a pushpin at the current location
let loc = Bing.Location(loc.Lat, loc.Long)
let pin = Bing.Pushpin loc
map.Entities.Clear()
map.Entities.Push pin
map.SetView(Bing.ViewOptions(Center = loc))// Keep updating your location regularly
JavaScript.SetInterval updateLocation 1000 |> ignorelet map =
Div []
|>! OnAfterRender (fun this ->
// Renders a Bing Maps control
let map = Bing.Map(this.Body, MapOptions)
map.SetMapType(Bing.MapTypeId.Road)
setMap map)// Returns the HTML markup for this control
Div [
label
Br []
map
] :> _
Figure 4: A Bing Map control and address bar showing your current location
This control uses the WebSharper mobile APIs to get the current GPS location. The IntelliFactory.WebSharper.Mobile namespace contains further utilities to interact with the underlying mobile device, including fetching accelerometer data, accessing the camera capabilities, or displaying native alert messages. Future versions of the WebSharper mobile API will also contain platform-specific extensions such as Bluetooth communication capabilities, etc.
Conclusion
If you haven’t used X-to-JavaScript tools to help you write web and mobile applications, you may wonder why there are so many of them and what makes people want to use them. WebSharper is a robust web development framework for F# and is in active use in a number of enterprise applications. It solves many of the web and mobile development issues you typically encounter and offers among others safe URLs; automatic resource tracking; and type-safe, composable abstractions for client-side markup and functionality; declarative-style web forms with client-side validation; and website values.
The WebSharper 2.3.28+ updates and the subsequent 2.4 release contain Visual Studio templates for mobile web development, and you can quickly try out and experiment with the two examples in this article using those templates. You can also download the sources here and here, including the final Android packages.
About the Author
Adam Granicz is a long-time F# insider and key community member, and the co-author of three F# books, including Expert F# 2.0 with Don Syme, the designer of the language. His company IntelliFactory specializes in consulting on the most demanding F# projects; shaping the future of the development of F# web, mobile and cloud applications; and developing WebSharper, the premiere web development framework for F#. You can reach him at granicz.adam {at} intellifactory.com, follow him on Twitter, or track him on FPish, the functional programming paradise.